Skip to content

feat: generate schema-based context, observer, handle with instrumentation-build#249

Draft
johanpel wants to merge 13 commits into
rapidsai:mainfrom
johanpel:instrumentation-build-handle
Draft

feat: generate schema-based context, observer, handle with instrumentation-build#249
johanpel wants to merge 13 commits into
rapidsai:mainfrom
johanpel:instrumentation-build-handle

Conversation

@johanpel

Copy link
Copy Markdown
Contributor

Description

This adds the ability for the instrumentation-build crate to generate {App}Context, {Entity}Observer and {Entity}Handle.

Nothing leverages the quent-fsm constraint yet to generate handles using a typestate pattern explored in #128, that will wrap around these handles.

Related Issues

Next step of #191

johanpel and others added 3 commits June 24, 2026 13:43
…rimitives

Rename `quent-instrumentation` to `quent-instrumentation-runtime` so the
schema-driven generator's `::quent_instrumentation_runtime::*` references
resolve, and add the primitives generated entity handles need:

- `Handle<E>`: per-instance handle holding the entity id, a `u128` once-emit
  bitset, and a shared `Arc<Observer<E>>`. `emit` sends a multi-cardinality
  event; `emit_once` guards a once-cardinality event by its bit index and
  fails with `ObserverError::OnceAlreadyEmitted` on a repeat.
- `EntityRef<T = ()>` backing `DataType::EntityRef` event fields, which the
  generator has referenced since rapidsai#218 with no type behind it.
- Re-export `build_info`, `EntityEvent`, `Event`, and `ExporterOptions` so
  generated code references one crate path.

The existing `Context`/`Observer` API is unchanged, so the macro path
(`quent-model`) is unaffected.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…xt from the schema

Emit the live instrumentation surface alongside the record/event types. Per
entity: an `EntityEvent` impl (stream name = the entity's snake-case name), a
cloneable `{Entity}Observer` factory, and a `{Entity}Handle` with one emit
method per event. Once-cardinality events take `&mut self` and are guarded by
a per-handle `u64` flag word (at most 64 per entity, else
`GenerateError::TooManyOnceEvents`); multi-events take `&self`. A
`{Schema}Context` builds every observer on construction and hands out cheap
`Arc` clones via `{entity}_observer()`. The generator lives under
`src/runtime/`, split into context/observer/handle.

Refine the runtime `Handle` to match the generated calls: `new()` mints a
fresh id, `with_id()` adopts a caller-supplied one, and the once-flag word is
a `u64`.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@johanpel johanpel added feature request New feature or request non-breaking Introduces a non-breaking change labels Jun 24, 2026
johanpel and others added 3 commits June 24, 2026 15:22
…example

Fix the stale `crates/instrumentation/benches/README.md` link in docs/faq.md
(rumdl MD057) to the renamed `crates/instrumentation-runtime/...` path and
reflow it under 80 columns. Trim the instrumentation-build example's comments:
drop the noop-sink aside and explain why the handle is `&mut` for once-events.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…amed crate

`cargo bench -p quent-instrumentation` no longer resolves after the
`quent-instrumentation` → `quent-instrumentation-runtime` rename; update the
three invocations to the new package name.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
johanpel and others added 7 commits June 25, 2026 16:21
Generate a fallback doc for record structs, event enums and variants, and
handle emit methods (used when the schema has no annotation) via a new
`doc_attr_or` helper, so every public type, variant, method, and function in
the generated instrumentation crate is documented. Fields stay annotation-only
to avoid restating their name and type. Also correct the context's
`*_observer()` doc: the accessors return an entity's event observer that mints
per-instance handles — they don't emit events themselves.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…text's ModelInfo

rapidsai#261 added `ModelInfo::analyzer_package`. The schema-driven path declares no
analyzer entry, so the generated `{Schema}Context::model_info()` sets it to
`None`, keeping the generated crate compiling after the merge.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…-exporter demo

Make a generated instrumentation library reference its backing crate as the
single required dependency, with `quent-exporter` the one exception (so a
consumer can select exporter features):

- Re-export from the runtime everything the generated code references — `Uuid`,
  `CustomAttributes`, `Event`/`EntityEvent`, `EntityRef`, `ObserverError`,
  `build_info` — and route generated field/method types through it
  (`::quent_instrumentation::Uuid`, `::CustomAttributes`). The generated file
  re-exports the data types, so a consumer needs no direct `uuid`/`attributes`
  dependency.
- Source `ExporterOptions` from `quent-exporter` rather than the runtime; the
  generated context's `try_new` takes `::quent_exporter::ExporterOptions`.
- Example: construct the context with a callback exporter that debug-prints
  events, factored into a `debug_printing_exporter()` helper.

Also rename the backing crate `quent-instrumentation-runtime` back to
`quent-instrumentation`, pairing with `quent-instrumentation-build`; the
generated code emits `::quent_instrumentation::…` accordingly.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…s to the impls

The `Exporter<T>` and `Importer<T>` traits no longer require `T: Serialize` /
`T: Deserialize`. Serialization is an exporter-implementation concern, so the
bound now lives only on the concrete exporters/importers that actually
(de)serialize (ndjson/msgpack/postcard/collector, which already declared it).
`CallbackExporter` type-erases its events, so it drops the bound and becomes a
genuine non-serializing exporter. The runtime's `Observer<T>`/`Handle<T>` drop
the bound too — they only forward events onto a channel; `Context::observer()`
keeps it, since it constructs the exporter.

Also fix the instrumentation-build module docs: the example used a nonexistent
`GenerateOptions` (the type is `Options`) and derives without `Serialize`.
Document that building an exporter requires the event/record types to be
`Serialize`.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature request New feature or request non-breaking Introduces a non-breaking change

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant